// /home/lester/HDPU/kinematix/kinematix/kRenderer.cs created with MonoDevelop
// User: lester at 22:11 17.06.2007
//

using System;
using System.Threading;
using System.Text;
using IrrlichtNETCP;
using IrrlichtNETCP.Extensions;

namespace kinematix
{
	
		
	
	public class kRenderer
	{
		public VideoDriver driver;
		public IrrlichtDevice device;
		public SceneManager scene;
		public GUIEnvironment env;
		
		public kGUI gui;
		
		public CameraSceneNode fpsCam;
		
		
		public ATMOSphere atmo;
		
		public kWorld world;

		public bool run;
		
		public float curr_time, last_time = 0;
		public kStack stack;
		public kObjectPicker picker;		
		
		
		public kRenderer(kPythonInterpreter _python)
		{
			device = new IrrlichtDevice(DriverType.OpenGL, new Dimension2D(640,480),32,
			                            false,true,false,false);
			
			if (device == null)
			{
				run = false;
				return;
			}
			run = true;
			
			
			string basecaption = "3d renderer";
			device.WindowCaption = basecaption;
			
			device.OnEvent += new OnEventDelegate (device_OnEvent);
			
			driver = device.VideoDriver;
			
			scene = device.SceneManager;
			
			world = new kWorld(null, device, -1);
			
			stack = new kStack(this);
			
			picker = new kObjectPicker(device);
			
			env = device.GUIEnvironment;
			env.Skin = env.CreateSkin(GUISkinTypes.WindowsMetallic);
			
			
			TTFace face = new TTFace();
			face.Load(_python.app.CurrentDir+"/media/LiberationSans-Regular.ttf");
			
	
			
			TTFont font = new TTFont( driver );
			font.Attach(face, 12);
			font.Antialias = true;
			font.Transparent = true;
			
			env.Skin.Font = font;
			
			gui = new kGUI(this, _python);

			device.FileSystem.WorkingDirectory = _python.app.CurrentDir+"/media";			
			
			gui.SetupBasicUI();

	
			atmo = new ATMOSphere(device.Timer, null, scene, -1);
			atmo.SkyTexture = driver.GetTexture("sky2.tga");
			atmo.SunTexture = driver.GetTexture("sun.tga");
			atmo.StarsTexture = driver.GetTexture("stars.bmp");
			atmo.CreateSkyPalette();
			atmo.CreateLensflare(driver.GetTexture("flares.jpg"));
			atmo.SetStartTime(2007,2,25,12,0);
			atmo.Speed = 60.0f;
			
			
			
			
			AnimatedMesh land_m = scene.AddHillPlaneMesh("_MyHill_", new Dimension2Df(250, 250),
			                                             new Dimension2D(5, 5),
			                                             0f, new Dimension2Df(0, 0),
			                                             new Dimension2Df(10, 10));
			scene.MeshManipulator.MakePlanarTextureMapping(land_m.GetMesh(0),0.06f);
			
			SceneNode land_s = scene.AddAnimatedMeshSceneNode(land_m);
			land_s.GetMaterial(0).Texture1 = driver.GetTexture("rockwall.bmp");
			
			scene.AddLightSceneNode(atmo.Sun,new Vector3D(0,100,0),Colorf.White,1500,-1);
			
			KeyMap keyMap = new KeyMap();
			keyMap.AssignAction(KeyAction.MoveForward,KeyCode.Key_W);
			keyMap.AssignAction(KeyAction.MoveBackward,KeyCode.Key_S);
			keyMap.AssignAction(KeyAction.StrafeLeft,KeyCode.Key_A);
			keyMap.AssignAction(KeyAction.StrafeRight,KeyCode.Key_D);
			
			fpsCam = scene.AddCameraSceneNodeFPS(null, 50, 70, false, keyMap);
			fpsCam.Position = Vector3D.From(0,10,-10);
			fpsCam.InputReceiverEnabled = false;
		
			device.CursorControl.Visible = true;
			atmo.Update(device.Timer.RealTime);
			
		}
		
		public bool Run()
		{
			
			float step = 0.001f;
			float dt = 0;
			
			last_time = 0;
			
			while (run&&device.Run())
			{
				
				if (!stack.Empty && stack.Lock())
				{
					stack.InvokeTop();
					stack.Unlock();
				}
				
				curr_time = device.Timer.Time;
				
				dt = (curr_time - last_time)*0.001f;
				
				if (dt > 0.01666) dt = 0.01666f;
				//Console.WriteLine(dt);			
				int nrofticks = (int)Math.Ceiling(dt/step);
				
				
				for (int i = 0; i <= nrofticks; i++)
				{
					world.Step(step*2);
				}
				
				
				driver.BeginScene(true, true, IrrlichtNETCP.Color.From(255,50,50,50));
				scene.DrawAll();
				env.DrawAll();
				driver.EndScene();
				last_time = curr_time;
			}
			device.Dispose();
			world.Destroy();				
			return true;
		}
		
		public void Quit()
		{
			run = false;		
		}
		
		bool device_OnEvent(IrrlichtNETCP.Event ev)
		{

			if (ev.Type == EventType.GUIEvent)
			{
				return gui.OnEvent(ev);
			}
			
			if (ev.Type == IrrlichtNETCP.EventType.KeyInputEvent)
			{
				switch (ev.KeyCode)
				{
					case KeyCode.Escape:
						Quit();
						return false;
					case KeyCode.Key_1:
						if (ev.KeyPressedDown)
						{
						world.AddBox(new Vector3D(0,2,0));
					}
						return false;
					case KeyCode.Key_2:
							if (ev.KeyPressedDown)
						{
						world.AddSphere();
					}
						return false;
					case KeyCode.Key_3:
						if (ev.KeyPressedDown)
							{
						world.AddCylinder();
					}
						return false;
					case KeyCode.Key_4:
						if (ev.KeyPressedDown)
						{
								world.AddCapsule();
					}
						return false;									
					case KeyCode.Space:
						if (ev.KeyPressedDown)
						{
						world.Run = !world.Run;
					}
						return false;								
					default:
						return false;
				}
			}
			
			if (ev.Type == IrrlichtNETCP.EventType.MouseInputEvent)
			{
				switch (ev.MouseInputEvent)
				{
					case MouseInputEvent.RMousePressedDown:
						device.CursorControl.Positionf = Position2Df.From(0.5f,0.5f);
						device.CursorControl.Visible = !device.CursorControl.Visible;
						fpsCam.InputReceiverEnabled = !fpsCam.InputReceiverEnabled;
						return false;
					case MouseInputEvent.LMousePressedDown:
						picker.OnClick(ev.MousePosition);
						return false;
					case MouseInputEvent.MouseMoved:
						picker.OnMouseMove(ev.MousePosition);							
						return false;
					default:
						return false;
				}
			}
		
			return false;
		}
		
		
		public kWorld World
		{
			get
				{
					return world;
				}
		}
		
		public kStack Stack
		{
			get
				{
					return stack;
				}
		}
		
		public IrrlichtDevice Device
		{
			get
				{
					return device;
				}
		}
		
		public kGUI Gui
		{
			get{
				return gui;
			}
		}
				
		
	}
}
